/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
module dwt.widgets.eventtable;


 
private import dwt.dwt;

private import dwt.internal.dwteventlistener;
private import dwt.util.eventhandler;
private import dwt.util.util;
private import dwt.util.vector;
private import dwt.widgets.event;
private import dwt.widgets.event;
private import dwt.widgets.listener;
private import dwt.widgets.typedlistener;

 
/**
 * Instances of this class implement a simple
 * look up mechanism that maps an event type
 * to a listener.  Muliple listeners for the
 * same event type are supported.
 */

/**
 * <Shawn> EventTable is modified to support D delegate mechanism
 */
 
public class EventTable {
	
	int [] types;
	Listener [] listeners;
	int level;
	
	TypedHandler[] handlers;

// <Shawn> hook a delegate handler
public void hook (TypedHandler handler) {
	assert(handler);	
	
	if (handlers is null) {
		handlers ~= handler;
		return;
	}
	int index = 0; 
	// find any null item to replace
	for(int i=0; i<handlers.length; ++i) {
		if(handlers[i] is null ) {
			handlers[i] = handler;	
			// Rearrange items
			rearrangeHandlers(i+1);
			break;
		}
		++index;
	}
	// not found
	if(index == handlers.length) {
		handlers ~= handler;		
	}
}


public void hook (int eventType, Listener listener) {
	if (types is null) types = new int [4];
	if (listeners is null) listeners = new Listener [4];
	int len = types.length, index = len - 1;
	while (index >= 0) {
		if (types [index] != 0) break;
		--index;
	}
	index++;
	if (index == len) {
		if (level == 0) {
			index = 0;
					
			for (int i=0; i<types.length; i++) {
				if (types [i] != 0) {
					types [index] = types [i];
					listeners [index] = listeners [i];
					index++;
				}
			}
			for (int i=index; i<types.length; i++) {
				types [i] = 0;
				listeners [i] = null;
			}
		}
		if (index == len) {
			int [] newTypes = new int [len + 4];
			System.arraycopy (types, 0, newTypes, 0, len);
			types = newTypes;
			Listener [] newListeners = new Listener [len + 4];
			System.arraycopy (cast(Object[])listeners, 0, cast(Object[])newListeners, 0, len);
			listeners = newListeners;
		}
	}
	types [index] = eventType;
	listeners [index] = listener;
}

public boolean hooks(int eventType) {
	for (int i=0; i<types.length; i++) {
		if (types [i] == eventType) return true;
	}
	foreach(TypedHandler hand; handlers){
		if(hand !is null  && hand.eventType == eventType)
			return true;
	}
	return false;
}

public void sendEvent(Event event) {
	level++;
	try {
		if (event.type == DWT.None) return;
		
		for (int i=0; i<types.length; i++) {
			if (types [i] == event.type) {
				Listener listener = listeners [i];
				if (listener !is null) listener.handleEvent (event);
			}
		}
		// proc delegates handlers
		foreach(TypedHandler hand; handlers) {
			if(hand !is null && hand.eventType == event.type){
				hand.handleEvent(event);
			}
		}
	} catch(Exception e){
		Util.trace(__FILE__ ~ ", " ~ e.toString());
	}finally {
		--level;
	}
}

public int size () {
	int count = 0;
	for (int i=0; i<types.length; i++) {
		if (types [i] != 0) count++;
	}
	foreach(TypedHandler hand; handlers){
		if(hand !is null) 
			++count;
	}
	return count;
}

private void remove (int index) {
	if (level == 0) {
		int end = types.length - 1;
		System.arraycopy (types, index + 1, types, index, end - index);
		System.arraycopy (cast(Object[])listeners, index + 1, cast(Object[])listeners, index, end - index);
		index = end;
	}
	types [index] = 0;
	listeners [index] = null;
}

public void unhook (int eventType, Listener listener) {
	if (types is null) return;
	for (int i=0; i<types.length; i++) {
		if (types [i] == eventType && listeners [i] is listener) {
			remove (i);
			return;
		}
	}
}

public void unhook (int eventType, DWTEventListener listener) {
	if (types is null) return;
	for (int i=0; i<types.length; i++) {
		if (types [i] == eventType) {
			if (cast(TypedListener)listeners [i]) {
				TypedListener typedListener = cast(TypedListener) listeners [i];
				if (typedListener.getEventListener () is listener) {
					remove (i);
					return;
				}
			}
		}
	}
}

// Unhook a delegate
public void unhook (TypedHandler handler) {
	if (handlers is null) return;
	for(int i=0; i<handlers.length; ++i) {
		TypedHandler hand = handlers[i];
		if(hand && hand.equals(handler)){
			hand = null;
			rearrangeHandlers(i);
			return;
		}
	}
}

private void rearrangeHandlers(int begin){
	// Rearrange items
	if(level == 0) {		
		int index = begin;
		for(int i = begin; i<handlers.length; ++i) {
			if(handlers[i] !is null) {
				handlers[index] = handlers[i];
				++index;
			}
		}
		for (int i=index; i<handlers.length; ++i) 
			handlers [i] = null;
	}
}

}
